//
// Copyright (c) 2010
// by Ashish Agrawal and Chris Paterra
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using CookComputing.XmlRpc;
using DotNetNuke.Entities.Tabs;
using SimpleBlog.Components.MetaWeblog;
using System.Collections.Generic;
using DotNetNuke.Security.Membership;
using DotNetNuke.Entities.Users;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Content.Common;
using Util = CookComputing.XmlRpc.Util;

namespace SimpleBlog
{

	public class MetaWeblogPost : XmlRpcService, IMetaWeblog
	{

		private PortalSettings _portalSettings;
		private int _tabId = -1;

		#region IMetaWeblog Members

		string IMetaWeblog.AddPost(string blogid, string username, string password, Post post, bool publish)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var id = string.Empty;

				// TODO: Implement your own logic to add the post and set the id
				return id;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		bool IMetaWeblog.EditPost(string postid, string username, string password, Post post, bool publish)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var result = false;

				// TODO: Implement your own logic to add the post and set the result
				return result;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		Post IMetaWeblog.GetPost(string postid, string username, string password)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var post = new Post();

				// TODO: Implement your own logic to update the post and set the post
				return post;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		CategoryInfo[] IMetaWeblog.GetCategories(string blogid, string username, string password)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var categoryInfos = new List<CategoryInfo>();
				//DotNetNuke.Entities.Content.Common.Util.GetTermController().
				//var colPortalCategories = new TermsInfo();

				// TODO: Implement your own logic to get category info and set the categoryInfos
				return categoryInfos.ToArray();
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		Post[] IMetaWeblog.GetRecentPosts(string blogid, string username, string password, int numberOfPosts)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var posts = new List<Post>();
				// TODO: Implement your own logic to get posts and set the posts

				return posts.ToArray();
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		MediaObjectInfo IMetaWeblog.NewMediaObject(string blogid, string username, string password, MediaObject mediaObject)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var objectInfo = new MediaObjectInfo();

				// TODO: Implement your own logic to add media object and set the objectInfo
				return objectInfo;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		bool IMetaWeblog.DeletePost(string key, string postid, string username, string password, bool publish)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var result = false;

				// TODO: Implement your own logic to delete the post and set the result
				return result;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		BlogInfo[] IMetaWeblog.GetUsersBlogs(string key, string username, string password)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				// get blog information based on moduleid/tabid/userid? (for now, identifier is moduleid hardcoded for testing)
				var objBlog = new BlogInfo() { blogid = "0", blogName = "Users Blog", url = "http://SimpleBlog/DesktopModules/SimpleBlog/MetaWeblogPost.ashx?tabid=61" };

				return new[] { objBlog };
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		/// <summary>
		/// Gets information about the user attempting to perform a blog action (via MetaWeblog).
		/// </summary>
		/// <param name="key"></param>
		/// <param name="username"></param>
		/// <param name="password"></param>
		/// <returns></returns>
		UserInfo IMetaWeblog.GetUserInfo(string key, string username, string password)
		{
			var objUser = ValidateUser(username, password, Context.Request.UserHostAddress);

			if (objUser != null)
			{
				var info = new UserInfo
							{
								Userid = objUser.UserID.ToString(),
								Firstname = objUser.FirstName,
								Lastname = objUser.LastName,
								Email = objUser.Email,
								Nickname = objUser.DisplayName
								//info.Url = objUser.Profile.Website;
							};
				return info;
			}
			throw new XmlRpcFaultException(0, "User is not valid!");
		}

		#endregion

		#region Private Methods

		/// <summary>
		/// Determines if a user is permitted to login, if so it returns the user DNN Core object. 
		/// </summary>
		/// <param name="username"></param>
		/// <param name="password"></param>
		/// <param name="ipAddress"></param>
		/// <returns>A DotNetNuke Core User object.</returns>
		private DotNetNuke.Entities.Users.UserInfo ValidateUser(string username, string password, string ipAddress)
		{
			DotNetNuke.Entities.Users.UserInfo userInfo;
			try
			{
				GetPortalSettings();

				var loginStatus = UserLoginStatus.LOGIN_FAILURE;
				userInfo = UserController.ValidateUser(_portalSettings.PortalId, username, password, "", _portalSettings.PortalName, ipAddress, ref loginStatus);

				if (loginStatus == UserLoginStatus.LOGIN_FAILURE)
				{
					// testing code that can be added to the end of the previous string.
					// PortalId:" + _portalSettings.PortalId + " PortalName:" + _portalSettings.PortalName + " portalAlias:" + portalAlias
					throw new XmlRpcFaultException(0, "Either the username or the password is invalid. ");
				}
			}
			catch (XmlRpcFaultException generatedExceptionName)
			{
				throw;
			}
			catch (Exception ex)
			{
				throw new XmlRpcFaultException(0, "An error occurred while trying to authenticate the user. ");
			}

			return userInfo;
		}

		/// <summary>
		/// 
		/// </summary>
		private void GetPortalSettings()
		{
			var portalID = -1;
			try
			{
				var request = Context.Request;

				if (request.QueryString["tabid"] != null)
				{
					_tabId = Int32.Parse(request.QueryString["tabid"]);
				}

				var cntTab = new TabController();
				var objTab = cntTab.GetTab(_tabId, portalID, false);

				portalID = objTab.PortalID;

				var cntAlias = new PortalAliasController();
				var colAlias = cntAlias.GetPortalAliasByPortalID(portalID);
				var objAlias = new PortalAliasInfo();

				foreach (string key in colAlias.Keys)
				{
					objAlias = colAlias[key];
					break;
				}

				var portalController = new PortalController();
				var objPortal = portalController.GetPortal(portalID);

				_portalSettings = new PortalSettings(_tabId, objAlias);

			}
			catch (XmlRpcFaultException ex)
			{
				throw;
			}
			catch (Exception generatedExceptionName)
			{
				throw new XmlRpcFaultException(0, "Please check your URL to make sure you entered the correct URL for your blog.  The blog posting URL is available through the blog settings for your blog.");
			}

		}

		#endregion

	}

	#region Structs

	/// <summary> 
	/// This struct represents information about a user's blog. 
	/// </summary> 
	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct BlogInfo
	{
		public string blogid;
		public string url;
		public string blogName;
	}

	/// <summary> 
	/// This struct represents information about a user. 
	/// </summary> 
	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct UserInfo
	{
		public string Userid;
		public string Firstname;
		public string Lastname;
		public string Nickname;
		public string Email;
		public string Url;
	}

	/// <summary> 
	/// This struct represents the information about a category that could be returned by the 
	/// getCategories() method. 
	/// </summary> 
	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct Category
	{
		public string CategoryId;
		public string CategoryName;
	}

	/// <summary> 
	/// This struct represents the information about a post that could be returned by the 
	/// editPost(), getRecentPosts() and getPost() methods. 
	/// </summary> 
	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct Post
	{
		[XmlRpcMissingMapping(MappingAction.Error)]
		[XmlRpcMember(Description = "Required when posting.")]
		public DateTime DateCreated;
		[XmlRpcMissingMapping(MappingAction.Error)]
		[XmlRpcMember(Description = "Required when posting.")]
		public string Description;
		[XmlRpcMissingMapping(MappingAction.Error)]
		[XmlRpcMember(Description = "Required when posting.")]
		public string Title;

		public object Postid;

		public string[] Categories;
		public Enclosure Enclosure;
		public string Link;
		public string PostAbstract;
		public string Permalink;
		public Source Source;
		public string Userid;

		public string WpSlug;
	}




	[Serializable]
	public struct CategoryInfo
	{
		public string Description;
		public string HtmlUrl;
		public string RssUrl;
		public string Title;
		public string Categoryid;
	}

	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct Enclosure
	{
		public int Length;
		public string Type;
		public string Url;
	}

	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct Source
	{
		public string Name;
		public string Url;
	}

	[XmlRpcMissingMapping(MappingAction.Ignore)]
	public struct MediaObject
	{
		public string Name;
		public string Type;
		public byte[] Bits;
	}

	[Serializable]
	public struct MediaObjectInfo
	{
		public string Url;
	}

	#endregion

}